﻿namespace Bronze.Network
{
    using System;
    using System.Collections;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Threading;

    public class CommonServer
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public Hashtable ClientConnections = new Hashtable();
        private Socket mListener;
        private int Port;
        private int totle_count;

        public event OnConnectedHandler mOnConnected;

        public event ClientErrorEvent mOnError;

        public event OnDataInHandler OnDataIn;

        public event OnDisconnectedHandler OnDisconnected;

        public CommonServer(int port)
        {
            this.Port = port;
        }

        private ClientConnection CreateClientConnection(IAsyncResult parameter)
        {
            ClientConnection connection = new ClientConnection(this.mListener.EndAccept(parameter));
            Interlocked.Increment(ref this.totle_count);
            connection.ConnectionId = this.totle_count;
            connection.CreateTime = DateTime.Now;
            connection.LastSendTime = DateTime.Now;
            log.InfoFormat("****创建连接:" + connection.ConnectionId);
            this.ClientConnections.Add(connection.ConnectionId, connection);
            if (this.mOnConnected != null)
            {
                this.mOnConnected(this, new SocketConnectedEventArgs(connection));
            }
            this.StartWaitingForData(connection);
            this.WaitForClient();
            return connection;
        }

        public void Disconnect(int ConnectionId)
        {
            if (this.ClientConnections.ContainsKey(ConnectionId))
            {
                ClientConnection connection = (ClientConnection)this.ClientConnections[ConnectionId];
                connection.Socket.Close();
                this.ClientConnections.Remove(connection.ConnectionId);
            }
        }

        private void HandleConnection(IAsyncResult parameter)
        {
            ClientConnection connection = null;
            try
            {
                connection = this.CreateClientConnection(parameter);
            }
            catch (ObjectDisposedException ex1)
            {
                log.Error("***HandleConnection自动断开连接}" + connection.ConnectionId ?? "", ex1);
                this.RaiseDisconnectedEvent(connection);
            }
            catch (SocketException exception)
            {
                this.RaiseErrorEvent(connection, exception);
            }
        }

        private void HandleConnectionData(ClientConnection connection, IAsyncResult parameter)
        {
            int length = connection.Socket.EndReceive(parameter);
            if (length == 0)
            {
                log.InfoFormat("***HandleConnectionData正常自动断开连接{0}", connection.ConnectionId);
                //表示正常的断开
                this.RaiseDisconnectedEvent(connection);
            }
            else
            {
                byte[] destinationArray = new byte[length];
                Array.Copy(connection.Buffer, 0, destinationArray, 0, length);
                if (this.OnDataIn != null)
                {
                    this.OnDataIn(this, new SocketDataInEventArgs(connection, destinationArray));
                }
                if (connection.Socket.Connected)
                {
                    this.StartWaitingForData(connection);
                }
            }
        }

        private void HandleIncomingData(IAsyncResult parameter)
        {
            ClientConnection asyncState = (ClientConnection)parameter.AsyncState;
            try
            {
                this.HandleConnectionData(asyncState, parameter);
            }
            catch (ObjectDisposedException ex1)
            {
                log.Error("***HandleIncomingData_ObjectDisposedException自动断开连接" + asyncState.ConnectionId, ex1);
                this.RaiseDisconnectedEvent(asyncState);
            }
            catch (SocketException exception)
            {
                if (exception.ErrorCode == 10054 || exception.ErrorCode == 10060)
                {
                    log.Error(string.Format("***HandleIncomingData_ErrorCode_自动断开连接{0},ErrorCode={1}", asyncState.ConnectionId, exception.ErrorCode), exception);
                    this.RaiseDisconnectedEvent(asyncState);
                }
                this.RaiseErrorEvent(asyncState, exception);
            }
        }

        private void HandleSendFinished(IAsyncResult parameter)
        {
            ClientConnection asyncState = (ClientConnection)parameter.AsyncState;
            asyncState.Socket.EndSend(parameter);
        }

        private void RaiseDisconnectedEvent(ClientConnection connection)
        {
            try
            {
                if ((this.OnDisconnected != null) && (connection != null))
                {
                    this.OnDisconnected(this, new SocketDisconnectedEventArgs(connection));
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                if (connection != null)
                {
                    this.ClientConnections.Remove(connection.ConnectionId);
                }
            }

        }

        private void RaiseErrorEvent(ClientConnection connection, SocketException error)
        {
            log.Error(string.Format("***RaiseErrorEvent错误{0},ErrorCode={1}", connection.ConnectionId, error.ErrorCode), error);
            if ((this.mOnError != null) && (connection != null))
            {
                this.mOnError(connection.EndPoint, error);
            }
        }

        public void Send(int ConnectionId, byte[] buffer)
        {
            if (this.ClientConnections.ContainsKey(ConnectionId))
            {
                ClientConnection state = (ClientConnection)this.ClientConnections[ConnectionId];
                try
                {
                    state.Socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(this.HandleSendFinished), state);
                }
                catch (ObjectDisposedException ex1)
                {
                    log.Error("***Send自动断开连接" + state.ConnectionId , ex1);
                    this.RaiseDisconnectedEvent(state);
                }
                catch (SocketException exception)
                {
                    this.RaiseErrorEvent(state, exception);
                }
            }
        }

        public void Shutdown()
        {
            this.mListener.Close();
            foreach (DictionaryEntry entry in this.ClientConnections)
            {
                ClientConnection connection = (ClientConnection)entry.Value;
                connection.Socket.Close();
            }
            this.ClientConnections.Clear();
        }

        public void Start()
        {
            this.mListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.mListener.Bind(new IPEndPoint(IPAddress.Any, this.Port));
            this.mListener.Listen(100000);
            this.WaitForClient();
        }

        private void StartWaitingForData(ClientConnection connection)
        {
            connection.Socket.BeginReceive(connection.Buffer, 0, connection.Buffer.Length, SocketFlags.None, new AsyncCallback(this.HandleIncomingData), connection);
        }

        private void WaitForClient()
        {
            this.mListener.BeginAccept(new AsyncCallback(this.HandleConnection), null);
        }
    }
}

